package JUC.第04章_锁;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 可重入锁
 * 可重入锁又名递归锁，是指在同一个线程在外层方法获取锁的时候，在进入内层方法会自动获取锁。
 * 说的有点抽象，下面会有一个代码的示例。
 * 对于Java ReentrantLock而言, 他的名字就可以看出是一个可重入锁，其名字是Reentrant Lock重新进入锁。
 * 对于Synchronized而言,也是一个可重入锁。可重入锁的一个好处是可一定程度避免死锁。
 * synchronized void setA() throws Exception{
 *     Thread.sleep(1000);
 *     setB();
 * }
 * synchronized void setB() throws Exception{
 *     Thread.sleep(1000);
 * }
 * 上面的代码就是一个可重入锁的一个特点，如果不是可重入锁的话，setB可能不会被当前线程执行，可能造成死锁。
 *
 * 隐式锁  (即synchronized关键字使用的锁)默认是可重入锁
 * 显示锁  ReentrantLock
 *
 * 每个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针。
 * 当执行 monitorenter 时，如果目标锁对象的计数器为零，那么说明它没有被其他线程所持有，
 * Java虚拟机会将该锁对象的持有线程设置为当前线程，并且将其计数器加 1。
 * 在目标锁对象的计数器不为零的情况下，如果锁对象的持有线程是当前线程，
 * 那么Java虚拟机可以将其计数器加1，否则需要等待，直至持有线程释放该锁。
 * 当执行 monitorexit 时，Java虛拟机则需将锁对象的计数器减1。计数器为零代表锁已被释放。
 *
 * ObjectMonitor.hpp  c的源码 中有几个关键属性
 * _owner               指向持有ObjectMonitor对象的线程
 * _WaitSet             存放处于wait状态的线程队列
 * _EntryList           存放处于等待锁block状态的线程队列
 * _recursions          锁的重入次数
 * _count               用来记录该线程获取锁的次数
 *
 */
public class B2_可重入锁 {
    public static void main(String[] args) {

        synchronized (B2_可重入锁.class){
            synchronized (B2_可重入锁.class){
                synchronized (B2_可重入锁.class){
                    System.out.println("synchronized 可重入锁，在同一个线程在外层方法获取锁的时候，在进入内层方法会自动获取锁");
                }
            }
        }

        System.out.println("***********************************************************");
        Lock lock=new ReentrantLock();//ReentrantLock递归锁 非公平锁  新版的
        lock.lock();        lock.lock();        lock.lock();

        System.out.println("ReentrantLock 可重入锁，在同一个线程在外层方法获取锁的时候，在进入内层方法会自动获取锁");

        lock.unlock();      lock.unlock();      lock.unlock();
    }
}
